package models

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/json"
	"errors"
	"github.com/zeromicro/go-zero/core/logx"
	"io"
	"net"
	"os"
	"time"
)

// License 表示许可证结构
type License struct {
	UniqueID   string    `json:"uniqueID"`   // 唯一标识（MAC 地址）
	ExpiryDate time.Time `json:"expiryDate"` // 有效期
}

// GenerateLicense 生成许可证并保存到文件
func GenerateLicense(macAddress string, expiryDays int, filename string, key []byte) error {
	// 检查密钥长度是否正确
	if len(key) != aes.BlockSize && len(key) != 24 && len(key) != 32 {
		return errors.New("密钥长度必须是16, 24或32字节")
	}

	license := License{
		UniqueID:   macAddress,
		ExpiryDate: time.Now().AddDate(0, 0, expiryDays),
	}

	// 将许可证结构体序列化为 JSON
	data, err := json.Marshal(license)
	if err != nil {
		return err
	}

	// 加密数据
	encryptedData, err := Encrypt(data, key)
	if err != nil {
		return err
	}

	// 将加密后的数据保存到文件
	return os.WriteFile(filename, encryptedData, 0644)
}

// ValidateLicense 验证许可证
func ValidateLicense(macAddress, filename string, key []byte) (bool, error) {
	// 检查密钥长度是否正确
	if len(key) != aes.BlockSize && len(key) != 24 && len(key) != 32 {
		return false, errors.New("密钥长度必须是16, 24或32字节")
	}

	// 读取许可证文件
	file, err := os.ReadFile(filename)
	if err != nil {
		return false, errors.New("许可证文件丢失或无法读取")
	}

	// 解密文件内容
	decodedData, err := Decrypt(file, key)
	if err != nil {
		logx.Errorf("许可证文件格式无效或解密失败")
		return false, errors.New("许可证文件格式无效或解密失败")
	}

	// 反序列化为 License 结构体
	var license License
	if err := json.Unmarshal(decodedData, &license); err != nil {
		return false, err
	}

	// 检查 MAC 地址是否匹配
	if license.UniqueID != macAddress {
		logx.Errorf("提供的 MAC 地址与许可证中存储的 MAC 地址不匹配")
		return false, errors.New("提供的 MAC 地址与许可证中存储的 MAC 地址不匹配")
	}

	// 检查许可证是否过期
	if time.Now().After(license.ExpiryDate) {
		logx.Errorf("许可证已过期")
		return false, errors.New("许可证已过期")
	}

	return true, nil // 许可证有效
}

// Pad 用于填充明文至完整块
func Pad(src []byte) []byte {
	padding := aes.BlockSize - len(src)%aes.BlockSize
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(src, padText...)
}

// UnPad 用于去掉填充
func UnPad(src []byte) ([]byte, error) {
	padding := src[len(src)-1]
	padLen := int(padding)
	if padLen > aes.BlockSize || padLen > len(src) {
		return nil, errors.New("无效的填充大小")
	}
	return src[:len(src)-padLen], nil
}

// Encrypt 使用 AES 加密数据
func Encrypt(plainText []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	// 填充明文
	paddedText := Pad(plainText)

	// 生成随机的 IV
	ciphertext := make([]byte, aes.BlockSize+len(paddedText))
	iv := ciphertext[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return nil, err
	}

	// 加密数据
	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(ciphertext[aes.BlockSize:], paddedText)

	return ciphertext, nil
}

// Decrypt 使用 AES 解密数据
func Decrypt(ciphertext []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	if len(ciphertext) < aes.BlockSize {
		return nil, errors.New("密文太短")
	}

	// 提取 IV
	iv := ciphertext[:aes.BlockSize]
	ciphertext = ciphertext[aes.BlockSize:]

	// 解密数据
	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(ciphertext, ciphertext)

	// 去除填充
	return UnPad(ciphertext)
}

// GetUniqueID 获取当前主机的唯一标识
func GetUniqueID() (string, error) {
	interfaces, err := net.Interfaces()
	if err != nil {
		return "", err
	}

	for _, iface := range interfaces {
		if iface.HardwareAddr != nil && len(iface.HardwareAddr) > 0 {
			return iface.HardwareAddr.String(), nil
		}
	}
	return "", errors.New("未找到有效的 MAC 地址")
}
